package com.rainbow.support.half.message.handler.producer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.rainbow.common.core.toolkit.SpringBeanUtil;
import com.rainbow.support.half.message.entity.HalfMessagePayload;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.lang.NonNull;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

import java.util.Objects;

/**
 * rocketMq半事务生产者
 * 通用逻辑块统一处理类
 * @author 傅为地
 */
@Slf4j
public abstract class AbstractProducerHandler implements HalfMsgProducerHandler {

    /**
     * TODO 生产者本地业务处理方法,需要具体业务方实现自己业务
     * 不同的生产者本地事务处理逻辑,具体处理自己本地事务逻辑
     * @param producer 生产者参数
     * @return 返回生产者本地业务处理结果
     */
    public abstract boolean producerProcess(@NonNull HalfMessagePayload producer);

    /**
     * 生产者处理,事务逻辑
     * 开启事务在本地处理之前,建议先将需要查询的参数准备好,然后在处理业务数据
     * 不推荐采用此方法处理生产者,消息体内日期格式可能存在问题
     * 推荐采用{@link #process(HalfMessagePayload producer)}
     * @param message 生产者参数
     * @return 返回生产者处理结果
     */
    @Deprecated
    @Override
    public boolean process(@NonNull String message) {
        log.info("RocketMq半事务生产者,接收参数==>producer:{}", message);
        HalfMessagePayload producer=parseHalfMessagePayload(message);
        prepareParams(producer);
        serviceProcess(producer,message);
        return true;
    }

    /**
     * 生产者处理,事务逻辑
     * 开启事务在本地处理之前,建议先将需要查询的参数准备好,然后在处理业务数据
     * @param producer 生产者参数
     * @return 返回生产者处理结果
     */
    @Override
    public boolean process(@NonNull HalfMessagePayload producer) {
        String message = JSON.toJSONStringWithDateFormat(producer, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteMapNullValue);
        log.info("RocketMq半事务生产者,接收参数==>producer:{}", message);
        Assert.notNull(producer,"RocketMq半事务生产者,接收参数有误,请检查数据!");
        Assert.notNull(producer.getGlobalId(),"RocketMq半事务生产者,全局事务编号不能为空,请检查数据!");
        Assert.notNull(producer.getBranchId(),"RocketMq半事务生产者,分支事务编号不能为空,请检查数据!");
        Assert.notNull(producer.getOriginBody(),"RocketMq半事务生产者,事务消息体不能为空,请检查数据!");
        Assert.notNull(producer.getCreator(),"RocketMq半事务生产者,消息发送人不能为空,请检查数据!");
        Assert.notNull(producer.getCreateTime(),"RocketMq半事务生产者,消息发送时间不能为空,请检查数据!");
        prepareParams(producer);
        serviceProcess(producer,message);
        return true;
    }

    /**
     * 本地业务处理,开启事务处理,
     * 事务回滚之后,异常继续上抛
     * 通知rocketMQ监听器回滚消息
     * @param producer 生产者参数
     * @param message  源消息信息
     * @return 本地事务处理结果
     */
    @Override
    public boolean serviceProcess(@NonNull HalfMessagePayload producer, @NonNull String message) {
        Boolean result = Objects.requireNonNull(SpringBeanUtil.getBean(TransactionTemplate.class),"事务组件初始化错误").execute(transactionStatus -> {
            try {
                saveProducerLog(producer,message);
                producerProcess(producer);
                return true;
            } catch (Exception error) {
                log.error("RocketMq生成者执行业务异常:", error);
                if (ObjectUtils.isNotEmpty(transactionStatus)) {
                    transactionStatus.setRollbackOnly();
                }
                throw error;
            }
        });
        return ObjectUtils.isEmpty(result) ? true : result;
    }

}
